﻿<!DOCTYPE html PUBLIC>
<html>
<head>
	<title>Benchmark JsRender</title>
	<link href="resources/perf-compare.css" rel="stylesheet" type="text/css" />
	<script src="http://code.jquery.com/jquery.js" type="text/javascript"></script>

	<script src="../jsrender.js" type="text/javascript"></script>
	<script src="resources/jquery.tmpl.js" type="text/javascript"></script>

	<script src="resources/handlebars.js" type="text/javascript"></script>
	<script src="resources/dot.js" type="text/javascript"></script>
</head>
<body>

<h3>Perf comparison</h3>

<em>Rendered content:</em><br /><br />
<table><tbody id="output"></tbody></table>

<br /><em>Times in milliseconds:</em>
<table><tbody id="results"></tbody></table>

<script type="text/javascript">
	var times = 250, ret, tmplString, htmlSample,
		tests = [],

		movie = { Name: "The <i>Red</i> Violin", ReleaseYear: "1998" },

		jqueryTmplTemplate = "<div><b>{{html Name}}</b> ({{html ReleaseYear}})<b>{{html Name}}</b> ({{html ReleaseYear}})<b>{{html Name}}</b> ({{html ReleaseYear}})<b>{{html Name}}</b> ({{html ReleaseYear}})</div>",
		jqueryTmplTemplateEncode = "<div><b>${Name}</b> (${ReleaseYear})<b>${Name}</b> (${ReleaseYear})<b>${Name}</b> (${ReleaseYear})<b>${Name}</b> (${ReleaseYear})</div>",
		jsRenderTemplate = "<div><b>{{:Name}}</b> ({{:ReleaseYear}})<b>{{:Name}}</b> ({{:ReleaseYear}})<b>{{:Name}}</b> ({{:ReleaseYear}})<b>{{:Name}}</b> ({{:ReleaseYear}})</div>",
		jsRenderTemplateEncode = "<div><b>{{>Name}}</b> ({{>ReleaseYear}})<b>{{>Name}}</b> ({{>ReleaseYear}})<b>{{>Name}}</b> ({{>ReleaseYear}})<b>{{>Name}}</b> ({{>ReleaseYear}})</div>",
		dotTemplate = "<div><b>{{=it.Name}}</b> ({{=it.ReleaseYear}})<b>{{=it.Name}}</b> ({{=it.ReleaseYear}})<b>{{=it.Name}}</b> ({{=it.ReleaseYear}})<b>{{=it.Name}}</b> ({{=it.ReleaseYear}})</div>",
		dotTemplateEncode = "<div><b>{{!it.Name}}</b> ({{!it.ReleaseYear}})<b>{{!it.Name}}</b> ({{!it.ReleaseYear}})<b>{{!it.Name}}</b> ({{!it.ReleaseYear}})<b>{{!it.Name}}</b> ({{!it.ReleaseYear}})</div>",
		handlebarsTemplate = "<div><b>{{{Name}}}</b> ({{{ReleaseYear}}})<b>{{{Name}}}</b> ({{{ReleaseYear}}})<b>{{{Name}}}</b> ({{{ReleaseYear}}})<b>{{{Name}}}</b> ({{{ReleaseYear}}})</div>",
		handlebarsTemplateEncode = "<div><b>{{Name}}</b> ({{ReleaseYear}})<b>{{Name}}</b> ({{ReleaseYear}})<b>{{Name}}</b> ({{ReleaseYear}})<b>{{Name}}</b> ({{ReleaseYear}})</div>",

		tmpl_doT = doT.template( dotTemplate ),
		tmpl_doTEncode = doT.template( dotTemplateEncode ),
		tmpl_jQueryTmpl =  $.template( null, jqueryTmplTemplate ),
		tmpl_JsRender = $.templates( null, jsRenderTemplate ),
		tmpl_jQueryTmplEncode =  $.template( null, jqueryTmplTemplateEncode ),
		tmpl_JsRenderEncode = $.templates( null, jsRenderTemplateEncode ),
		tmpl_handlebars = Handlebars.compile( handlebarsTemplate ),
		tmpl_handlebarsEncode = Handlebars.compile( handlebarsTemplateEncode );

	// For Handlebars, make initial rendering call to do first compilation.
	htmlSample = tmpl_handlebars( movie );
	tmpl_handlebarsEncode( movie);
	$( "#output" ).html( htmlSample );

	function test( label, times, places, cb ) {
		var target = $( "<tr><td>" + label + ": </td></tr>" ).appendTo( "#results" );
		tests.push( function() {
			var endTime, result,
				count = times,
				startTime = new Date().getTime();

			while (count--) {
				cb();
			}
			endTime = new Date().getTime();
			result = ((( endTime-startTime ) * 1000 ) / times);
			target.append( "<td class='result'>" + result.toFixed( places ) + "</td>");
			runNextTest();
		});
	}

	function runNextTest() {
		var next;
		if (next = tests.shift()) {
			setTimeout( next, 0 );
		} else {
			$( "#results" ).append( "<tr><td colspan='2'><em>Tests complete...</em></td></tr>" );
		}
	}

	// Test render to string perf
	$( "#results" ).append( "<tr><td colspan='2'>________________________________________________________</td></tr>" );
	$( "#results" ).append( "<tr><td colspan='2'><b>Optimized render to string</b></td></tr>");

	test( "jQuery Template", times * 500, 1, function() {
		ret = tmpl_jQueryTmpl($, { data: movie }).join("");
	});
	test( "doT", times * 500, 1, function() {
		ret = tmpl_doT(movie);
	});
	test( "Handlebars", times * 500, 1, function() {
		ret = tmpl_handlebars(movie);
	});
	test( "JsRender <em>(optimized .fn() method - for simple templates)</em>", times * 500, 1, function() {
		ret = tmpl_JsRender.fn( movie );
	});
	test( "JsRender <em>(.render() method - full view-hierarchy features)</em>", times * 500, 1, function() {
		ret = tmpl_JsRender.render( movie );
	});

	// Test html encoding perf
	$( "#results" ).append( "<tr><td colspan='2'>________________________________________________________</td></tr>" );
	$( "#results" ).append( "<tr><td colspan='2'><b>Render to string, with HTML encoding</b></td></tr>");

	test( "jQuery Template", times * 50, 1, function() {
		ret = tmpl_jQueryTmplEncode($, { data: movie }).join("");
	});
	test( "doT", times * 50, 1, function() {
		ret = tmpl_doTEncode( movie );
	});
	test( "Handlebars", times * 50, 1, function() {
		ret = tmpl_handlebarsEncode( movie );
	});
	test( "JsRender <em>(optimized .fn() method)</em>", times * 50, 1, function() {
		ret = tmpl_JsRenderEncode.fn( movie );
	});

	// Test full features perf
	$( "#results" ).append( "<tr><td colspan='2'>________________________________________________________</td></tr>" );
	$( "#results" ).append( "<tr><td colspan='2'><b>Full features - view hierarchy etc.</b></td></tr>");

	test( "jQuery Template full features - inserted in DOM", times * 5, 0, function() {
		$( "#output" ).empty();
		$.tmpl( tmpl_jQueryTmpl, movie ).appendTo( "#output" );
	});
	test( "JsRender full features - inserted in DOM", times * 5, 0, function() {
		$( "#output" ).html( tmpl_JsRender.render( movie ));
	});

	// Test compile perf
	$( "#results" ).append( "<tr><td colspan='2'>________________________________________________________</td></tr>" );
	$( "#results" ).append( "<tr><td colspan='2'><b>Compile</b></td></tr>");

	test( "jQuery Template compile", times * 5, 0, function() {
		tmpl_jQueryTmpl = $.template( jqueryTmplTemplate );
	});
	test( "doT compile", times * 5, 0, function() {
		tmpl_doT = doT.template( dotTemplate );
	});
	test( "Handlebars compile", times * 5, 0, function() {
		var tmpl = Handlebars.compile( handlebarsTemplateEncode );
		// For Handlebars, make initial rendering call to do first compilation.
		tmpl( movie );
	});
	test( "JsRender compile", times * 5, 0, function() {
		tmpl_JsRender = $.templates( "test", jsRenderTemplate );
	});

	$( "#results" ).append( "<tr><td colspan='2'>________________________________________________________</td></tr>" );

	runNextTest();
</script>

</body>
</html>
